/*
 * Copyright 2011 Romain Gilles
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jvdb;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.util.ContextInitializer;
import ch.qos.logback.core.*;
import org.slf4j.LoggerFactory;

import java.util.Calendar;
import java.util.Locale;

import static org.jvdb.ConfigUtil.LOGGER_BASE_NAME;

/**
 * Created by IntelliJ IDEA. User: romain.gilles Date: 1/12/11 Time: 11:21 PM To
 * change this template use File | Settings | File Templates.
 */
enum Mode {
    NONE() {
        @Override
        boolean isActivated() {
            return false;
        }
    }, TDB() {
        @Override
        ConnectionFactory newConnectionFactory() {
            return new TdbConnectionFactory();
        }
    },
    VDB() {
        @Override
        ConnectionFactory newConnectionFactory() {
            return new VdbConnectionFactory();
        }
    };

    private static final String LOGGER_BASE = LOGGER_BASE_NAME + '.';
    private static final String LOGGER_MODE_NAME = LOGGER_BASE_NAME + ".mode";
    private static final String LOGGER_CONSOLE_NAME = LOGGER_BASE_NAME + ".console";
    private static final String LOGGER_FILE_NAME = LOGGER_BASE_NAME + ".file";

    private static final org.slf4j.Logger logger_ = LoggerFactory.getLogger(LOGGER_MODE_NAME);

    private static final String LOG_PATTERN_LAYOUT = "%d{yyyy/MM/dd HH:mm:ss.SSS} | %-30.-30t |  [jvdb] - %m%n";

    static {
        LoggerContext lc = getLoggerContext();
        if (new ContextInitializer(lc).findURLOfDefaultConfigurationFile(false) == null) {
            //deseable basic configuration: see ch.qos.logback.classic.util.ContextInitializer#autoConfig()
            //see ch.qos.logback.classic#BasicConfigurator
            Logger rootLogger = lc.getLogger(Logger.ROOT_LOGGER_NAME);
            rootLogger.setLevel(Level.OFF);
            rootLogger.detachAndStopAllAppenders();
        }
        init();
    }

    private static class JvdbPatternLayout extends LayoutBase<ILoggingEvent> {
        public String doLayout(ILoggingEvent event) {
            String message = event.getFormattedMessage();
            StringBuilder buffer = new StringBuilder(30 + message.length());
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(event.getTimeStamp());
            DateConverter.format(calendar, buffer);
            buffer.append(" | ");
            append3DigitField(buffer, Thread.currentThread().getId());
            buffer.append(" | [jvdb] - ");
            buffer.append(message);
            buffer.append(CoreConstants.LINE_SEPARATOR);
            return buffer.toString();
        }
    }

    private static StringBuilder append3DigitField(StringBuilder result, long value) {
        if (value < 100)
            result.append('0');
        if (value < 10)
            result.append('0');
        result.append(value);
        return result;
    }

    static void init() {
        Mode mode = getMode();
        if (mode != NONE) {
            logger_.debug("test logger configuration for mode: {}", mode.name());
            Logger logger = (Logger) mode.getLogger();
            if (!logger.isInfoEnabled()) {
                logger.setLevel(Level.INFO);
            }
            LoggerContext lc = getLoggerContext();

            if (!(logger.getAppender(LOGGER_FILE_NAME) instanceof OutputStreamAppender<?>)) {
                FileAppender<ILoggingEvent> fileAppender = new FileAppender<ILoggingEvent>();
                fileAppender.setContext(lc);
                logger.addAppender(fileAppender);
                fileAppender.setName(LOGGER_FILE_NAME);
                fileAppender.setAppend(false);
                fileAppender.setFile(ConfigUtil.getLogfilePath());
                fileAppender.setLayout(createPatternLayout(lc));
                fileAppender.start();
            }
            if (ConfigUtil.isConsoleEnable()
                    && !(logger.getAppender(LOGGER_CONSOLE_NAME) instanceof OutputStreamAppender<?>)) {
                logger.setAdditive(true);
                ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<ILoggingEvent>();
                appender.setContext(lc);
                logger.addAppender(appender);
                appender.setName(LOGGER_CONSOLE_NAME);
                appender.setLayout(createPatternLayout(lc));
                appender.start();
            }
        }
    }

    private static LoggerContext getLoggerContext() {
        return (LoggerContext) LoggerFactory
                .getILoggerFactory();
    }

    private static Layout<ILoggingEvent> createPatternLayout(LoggerContext lc) {
        Layout<ILoggingEvent> pl = new JvdbPatternLayout();
        pl.setContext(lc);
        pl.start();
        return pl;
    }

    org.slf4j.Logger getLogger() {
        return LoggerFactory.getLogger(getLoggerName());
    }

    private String getLoggerName() {
        return LOGGER_BASE + getNormalizedName();
    }

    String getNormalizedName() {
        return name().toLowerCase(Locale.ENGLISH);
    }

    static Mode getMode() {
        for (Mode mode : Mode.values()) {
            if (mode.isActivated()) {
                return mode;
            }
        }
        return NONE;
    }

    boolean isActivated() {
        return ConfigUtil.contains(getNormalizedName());
    }

    ConnectionFactory newConnectionFactory() {
        return new SimpleConnectionFactory();
    }
}
